package cn.yunlang.zhangZhongFei.exception;


import cn.yunlang.zhangZhongFei.vo.response.R;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Objects;



@ControllerAdvice
public class GlobalExceptionHandler {

    private final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 系统异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public R handleException(Exception e) throws Exception {
        log.error("Default Exception: ", e);
        if (e instanceof AccessDeniedException || e instanceof AuthenticationException){
            throw e;
        }
        return R.error(ErrorCodeExceptionEnum.SYSTEM_ERROR);
    }

    /**
     * 自定义异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ErrorCodeException.class)
    @ResponseBody
    public R handleInsuranceException(ErrorCodeException e) {
        log.error("errorCodeException: ", e);
        return R.error(500, e.getMsg());
    }

    /**
     * MethodArgumentNotValidException 异常捕获
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public R notValidExceptionHandle(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        Objects.requireNonNull(bindingResult.getFieldError());
        return R.error(ErrorCodeExceptionEnum.PARAM_ERROR.getCode(),
                bindingResult.getFieldError().getField() + " " + bindingResult.getFieldError().getDefaultMessage());
    }

    /**
     * BindException异常捕获
     *
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class)
    public R bindExceptionHandler(BindException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String messages = StringUtils.join(fieldErrors.stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage).toArray(), ";");
        return R.error(ErrorCodeExceptionEnum.PARAM_ERROR.getCode(), messages);
    }

    /**
     * ConstraintViolationException 异常捕获
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public R ConstraintViolationException(ConstraintViolationException e) {
        ConstraintViolation<?> violation = e.getConstraintViolations().iterator().next();
        String path = ((PathImpl) violation.getPropertyPath()).getLeafNode().getName();
        String resultMessage = String.format("参数%s%s", path, violation.getMessage());
        return R.error(ErrorCodeExceptionEnum.PARAM_ERROR.getCode(),
                resultMessage);
    }

    /**
     * MissingServletRequestParameterException 异常捕获
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public R MissingServletRequestParameterException(MissingServletRequestParameterException e) {
        String name = e.getParameterName();
        String type = e.getParameterType();
        String value = e.getMessage();
        log.info(value);
        String message = String.format("参数%s为空", name, type, value);
        return R.error(ErrorCodeExceptionEnum.PARAM_ERROR.getCode(),
                message);
    }



    /**
     * HttpRequestMethodNotSupportedException  异常捕获
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public R httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e) {
        return R.error(ErrorCodeExceptionEnum.REQUEST_METHOD_ERROR);
    }
}
